import { Vector } from '../vector'
import {Couple} from './couple'
import {Line} from './line'
import {PersonHeight, GenerationSpace, BrotherLineHeight, TreeSpacing} from './person'
import {deepCopy} from '../util'

//绘制家族树的帮助类。从底层节点依次分析到高层节点，里面含有分析出的couple位置和线段的位置。
//缓存每层的宽度，当两个TreeSet融合为一个的时候，要考虑每层的宽度是否有重合，如果是，就要调整上层的宽度，让它宽一点。
class TreeSet {
  constructor(tree_drawer, options = {}) {
    this.tree_drawer = tree_drawer // FamilyTreeDrawer对象
    this.family_id = 0  //当前家族id缓存
    this.couples = {}  //所有Couple, 格式: level -> couple数组，数组的排列是按照实际的位置从左到右排列。
    this.lines = []  //Line数组
    this.top_couple = null  //顶部节点, Couple对象，是couples中level最小一个元素的引用
    this.pos = new Vector(0, 0)  //pos表示顶部couple的上面中点的位置

    this.options = options  //绘制参数
    this.select_person = null  //当前选中的Person对象
    this.last_select_person = null  //上次选中的Person对象
    this.tap_person = null  //当前按下的人
  }

  //用一个couple节点初始化（带level字段）
  InitByCouple(couple_data) {
    let cpl = new Couple(this.tree_drawer, new Vector(0, 0), couple_data, this.options)
    this.couples[cpl.data.level] = [cpl]
    this.top_couple = cpl
  }

  //绘制
  Draw() {
    for (let level in this.couples) {
      let arr = this.couples[level]
      for (let i = 0; i < arr.length; i++) {
        arr[i].Draw()
      }
    }
    for (let i = 0; i < this.lines.length; i++) {
      this.lines[i].Draw()
    }
  }

  //移动
  Move(vec) {
    if (vec.IsZero()) {
      return
    }
    this.pos.Add(vec)
    for (let level in this.couples) {
      let arr = this.couples[level]
      for (let i = 0; i < arr.length; i++) {
        arr[i].Move(vec)
      }
    }
    for (let i = 0; i < this.lines.length; i++) {
      this.lines[i].Move(vec)
    }
  }

  //获取和长辈连接的位置
  GetParentConnectPos() {
    if (this.top_couple && !this.top_couple.IsEmpty()) {
      return this.top_couple.GetParentConnectPos()
    } else {
      return this.pos.Copy()
    }
  }

  //一组兄弟和父母合并
  //parent_couple是父母(Couple对象, 位置是0,0)，brothers是TreeSet的数组，表示该父母下的所有子女，按从小到大的顺序排列。返回合并后的TreeSet
  //parent_couple只可能在顶级节点为空(wife和husband都等于0)
  static BuildParent(tree_drawer, parent_couple, brothers, options) {
    //数据校验
    if (!(parent_couple instanceof Couple)) {
      throw "BuildParent: parent_couple is not Couple!"
    }
    let parent_id = parent_couple.data.child  //父母couple id
    if (!(brothers instanceof Array)) {
      throw "BuildParent: brothers is not an Array!"
    }
    if (brothers.length == 0) {
      throw "BuildParent: brothers is empty!"
    }
    for (let i = 0; i < brothers.length; i++) {
      if (!(brothers[i] instanceof TreeSet)) {
        throw "BuildParent: brothers has not TreeSet element!"
      }
      if (!brothers[i].top_couple) {
        throw "BuildParent: brother has not top_couple!"
      }
      if (brothers[i].top_couple.data.parent != parent_id) {
        throw "BuildParent: brothers parent not fit!"
      }
    }

    //先画brothers自身
    //返回兄弟 + 连接线
    //移动： 让第一个brother的位置是(0, 0), 其他brother做相应移动
    let most_right_couples = {}  //从左到右遍历brothers，缓存： level -> 该层当前最右couple。不光要相邻的合并，不相邻的也可能相互影响。所以用这个变量表示每个层级的最右侧。
    let curr_offset = 0  //当前brother的总偏移
    let bro_len = brothers.length
    for (let i = 0; i < bro_len; i++) {

      //只对重合的level进行计算
      let curr_bro = brothers[i]
      let max_width = 0  //当前这个brother距离左边brother的距离
      for (let level in curr_bro.couples) {
        if (level in most_right_couples) {
            //注意排序是实际位置从左到右
            let left_couple = most_right_couples[level]
            let right_couple = curr_bro.couples[level][0]
            if (i != 0) {
              let last_brother = brothers[i-1]
              let left_width = left_couple.pos.Copy().Sub(last_brother.pos).x + left_couple.GetFixedSize().x / 2  //左边占用宽度, 可能为负
              let right_width = curr_bro.pos.Copy().Sub(right_couple.pos).x + right_couple.GetFixedSize().x / 2 //右边占用宽度, 可能为负
              let need_width = left_width + right_width + TreeSpacing
              if (need_width > max_width) {
                max_width = need_width
              }
            }
        }
      }
      curr_offset += max_width
      curr_bro.Move(new Vector(curr_offset, 0))  //后面的移动到右边

      for (let level in brothers[i].couples) {
        //为下一个brother找到在他之前的最右元素
        let arr = brothers[i].couples[level]
        if (arr.length > 0) {
          most_right_couples[level] = arr[arr.length - 1]
        }
      }
    }

    //将所有brothers和parent_couple一起，合成新对象
    let result = new TreeSet(tree_drawer, options)
    result.top_couple = parent_couple

    //根据现在brothers的坐标信息，预估出parent_couple的位置，作为结果TreeSet位置。这样就保持了TreeSet位置和brothers位置的一致性。
    let middle
    if (bro_len > 1) {
      middle = brothers[0].GetParentConnectPos().Add(brothers[bro_len - 1].GetParentConnectPos()).x / 2
      if (!(parent_couple.IsEmpty())) {
        result.pos = new Vector(middle, -GenerationSpace - parent_couple.GetFixedSize().y)
        parent_couple.Move(result.pos)
      } else {
        result.pos = new Vector(middle, -BrotherLineHeight)
      }
    } else {
      middle = brothers[0].GetParentConnectPos().x
      if (!(parent_couple.IsEmpty())) {
        result.pos = new Vector(middle, -GenerationSpace - parent_couple.GetFixedSize().y)
        parent_couple.Move(result.pos)
      } else {
        result.pos = new Vector(middle, 0)
      }
    }

    result.couples = {}  //合并所有couple
    result.couples[parent_couple.data.level] = [parent_couple]
    for (let i = 0; i < brothers.length; i++) {
      for (let level in brothers[i].couples) {
        let arr = brothers[i].couples[level]
        if (level in result.couples) {
          result.couples[level] = [...result.couples[level], ...arr]
        } else {
          result.couples[level] = arr
        }
      }
    }

    result.lines = []  //同时生成兄弟连接线
    for (let i = 0; i < bro_len; i++) {
      result.lines = [...result.lines, ...brothers[i].lines]
      if (bro_len > 1) {
        result.lines.push(new Line(tree_drawer, brothers[i].GetParentConnectPos(), brothers[i].GetParentConnectPos().Sub(new Vector(0, BrotherLineHeight))))
      }
    }
    if (bro_len > 1) {
      result.lines.push(new Line(
        tree_drawer,
        brothers[0].GetParentConnectPos().Sub(new Vector(0, BrotherLineHeight)), 
        brothers[brothers.length - 1].GetParentConnectPos().Sub(new Vector(0, BrotherLineHeight))
      ))
    }
    if (!(parent_couple.IsEmpty())) {
      let parent_conn_pos = parent_couple.GetChildConnectPos()
      let child_conn_pos
      if (bro_len > 1) {
        child_conn_pos = new Vector(middle, -BrotherLineHeight)
      } else {
        child_conn_pos = brothers[0].GetParentConnectPos()
      }
      result.lines.push(new Line(tree_drawer, parent_conn_pos, child_conn_pos))
    }
    
    //回复原位置(0,0)
    result.Move(result.pos.Copy().Scale(-1))
    return result

  }

  //根据 with_level_data 构建TreeSet, 关于with_level_data的格式，请参考FamilyTreeData对象的_calcOriginDataLevel方法的返回
  static CreateTreesetFromWithLevelData(tree_drawer, with_level_data, options = {}) {
    let sorted_data = deepCopy(with_level_data)
    let ts = null  //待构建的treeset
    if (sorted_data.length == 0) {
      ts = new TreeSet(tree_drawer, options)
      this.treeset_cache[family_id] = ts
      return
    }
    let sorted_data_map = {}  //id -> data
    for (let i = 0; i < sorted_data.length; i++) {
      sorted_data_map[sorted_data[i].child] = sorted_data[i]
    }

    //依次生成最终TreeSet
    let tree_set_map = {}  // id -> TreeSet对象
    while (sorted_data.length > 0) {
      if (sorted_data.length == 1) {
        if (sorted_data[0].child in tree_set_map) {
          ts = tree_set_map[sorted_data[0].child]
        } else {
          ts = new TreeSet(tree_drawer, options)
          ts.InitByCouple(sorted_data[0])
        }
        break
      }

      //从左到右寻找一批兄弟，level和parent一致
      let brother_num = 0
      let curr_level = sorted_data[0].level 
      let curr_parent = sorted_data[0].parent
      for (let i = 0; i < sorted_data.length; i++) {
        if (sorted_data[i].level == curr_level && sorted_data[i].parent == curr_parent) {
          brother_num++
        } else {
          break
        }
      }

      if (brother_num == sorted_data.length) {
        throw "all brother has no parent!"
      }
      if (!(curr_parent in sorted_data_map)) {
        throw "parent not in sorted_data_map!"
      }

      let brothers = []  //TreeSet数组
      for (let i = 0; i < brother_num; i++) {
        let item = sorted_data.shift()  //从头删除一个元素并返回
        let curr_tree_set
        if (item.child in tree_set_map) {
          curr_tree_set = tree_set_map[item.child]
          delete tree_set_map[item.child]
        } else {
          curr_tree_set = new TreeSet(tree_drawer, options)
          curr_tree_set.InitByCouple(item)
        }
        brothers.push(curr_tree_set)
      }

      let parent_couple = new Couple(tree_drawer, new Vector(0,0), sorted_data_map[curr_parent], this.options)
      let parent_treeset = TreeSet.BuildParent(tree_drawer, parent_couple, brothers, options)
      tree_set_map[curr_parent] = parent_treeset
      
    }
    return ts
  }

  //获取某个位置(vector)选中的人，返回Person对象，没有选中返回null
  GetSelectPerson(pos) {
    for (let level in this.couples) {
      let arr = this.couples[level]
      for (let i = 0; i < arr.length; i++) {
        let selectPerson = arr[i].GetSelectPerson(pos)
        if (selectPerson) {
          return selectPerson
        }
      }
    }
    return null
  }

  //手指按下回调
  TapDown(pos) {
    this.has_down_finger = true  //未松开的单指
    this.first_move = true  //是否是按下后的第一个移动回调
    this.tap_down_pos = pos
    this.tap_down_tick = (new Date()).getTime()
    if (this.options.can_select_person) {
      this.last_select_person = this.select_person
      let person = this.GetSelectPerson(pos)
      if (person) {
        if (this.select_person) {
          this.select_person.SetSelect(false)
        }
        this.select_person = person
        this.select_person.SetSelect(true)
      } else if (this.options.cancel_select_person) {
        if (this.select_person) {
          this.select_person.SetSelect(false)
        }
        this.select_person = null
      }
    }

    if (this.options.can_long_press_person) {
      if (this.tap_person) {
        this.tap_person.SetTap(false)
        this.tap_person = null
      }
      let person = this.GetSelectPerson(pos)
      if (person) {
        this.tap_person = person
        this.tap_person.SetTap(true)
      }
    }
  }

  //单值移动回调
  TapMove(pos) {
    if (this.first_move) {
      this.first_move = false
      //按下后的第一个移动
      this.RecoverLastSelectPerson()
    } 
  }

  //手指松开回调
  TapUp(pos) {
    this.has_down_finger = false

    if (this.tap_person) {
      this.tap_person.SetTap(false)
      this.tap_person = null
    }

    if (!this.tap_down_pos) {
      return
    }
    if (pos.Copy().Sub(this.tap_down_pos).Size() < 2) {
      //正常的手指松开(和手指按下同一个坐标，注意：手指按下后移动坐标并不会改变)
      let moved = !this.first_move   //是否移动过
      if (this.tap_down_tick && !moved) {

        let person = this.GetSelectPerson(this.tap_down_pos)
        if (person) {
          this.tree_drawer.SelectPersonCallback(person.id)
        }

        if (this.options.can_long_press_person) {
          if ((new Date()).getTime() - this.tap_down_tick >= 0) {
            console.log('long press.....')
            if (person) {
              wx.navigateTo({
                url: '../family/person?person=' + person.id + '&family=' + this.family_id
              })
            }
          }
          
        }
      }
    }
    this.tap_down_pos = null
    this.tap_down_tick = null
  }

  //开始双指
  DoubleTapStart() {
    if (this.tap_person) {
      this.tap_person.SetTap(false)
      this.tap_person = null
    }
    if (this.has_down_finger) {
      //双指之前有未松开的单指，则认为未松开的单指就是双指其中之一，取消该单指的效果
      this.RecoverLastSelectPerson()
    }
  }

  //恢复上一刻选中的人
  RecoverLastSelectPerson() {
    if (this.select_person) {
      this.select_person.SetSelect(false)
    }
    if (this.last_select_person) {
      this.last_select_person.SetSelect(true)
    }
    this.select_person = this.last_select_person
    this.last_select_person = null
  }

  //清楚tap缓存
  ClearTap() {
    delete this.has_down_finger
    delete this.first_move
    delete this.tap_down_pos
    delete this.tap_down_tick
    
    if (this.tap_person) {
      this.tap_person.SetTap(false)
      this.tap_person = null
    }

    if (this.select_person) {
      this.select_person.SetSelect(false)
    }
    if (this.last_select_person) {
      this.last_select_person.SetSelect(false)
    }
    this.select_person = null
    this.last_select_person = null
  }
}

module.exports = {
  TreeSet
}